package org.ytor.core.sysapi.scheduler.logic;

import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;
import org.ytor.common.exception.BaseException;
import org.ytor.common.scheduler.Task;
import org.ytor.common.scheduler.support.timewheel.ITimeWheelScheduler;
import org.ytor.common.scheduler.support.timewheel.TimeWheelTask;
import org.ytor.common.util.Strs;
import org.ytor.core.scheduler.task.ParameterTask;
import org.ytor.core.sqlflow.BaseLogic;
import org.ytor.core.sysapi.scheduler.model.SysSchedulerTask;
import org.ytor.core.sysapi.scheduler.repository.SysSchedulerTaskRepository;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * created by yangtong on 2025年7月9日 13:20:32
 * <br/>
 * 基础表结构服务
 * <br/>
 */
@Slf4j
@Service
@Order()
@RequiredArgsConstructor
public class SysSchedulerTaskLogic extends BaseLogic<SysSchedulerTask, SysSchedulerTaskRepository> {

    private final ITimeWheelScheduler scheduler;
    private final Map<String, Task> taskMap;

    /**
     * 映射：定时任务的数据库id -> 时间轮中的任务id
     */
    private final Map<String, String> taskIdMap = new ConcurrentHashMap<>();

    @PostConstruct
    public void init() {
        log.info("准备加载定时任务...");
        try {
            List<SysSchedulerTask> tasks = repository.queryList(w -> w.eq(SysSchedulerTask::getStatus, 1));
            for (SysSchedulerTask schedulerTask : tasks) {
                String wheelTaskId = addSchedulerTask(schedulerTask);
                if (wheelTaskId != null) {
                    taskIdMap.put(schedulerTask.getId(), wheelTaskId);
                }
            }
            log.info("定时任务加载完毕! 共加载{}个任务", taskIdMap.size());
        } catch (Exception e) {
            log.error("加载定时任务失败", e);
            throw new RuntimeException("加载定时任务失败", e);
        }
    }

    public void enable(String id) {
        SysSchedulerTask schedulerTask = repository.queryById(id);
        if (schedulerTask == null) {
            throw new RuntimeException("定时任务不存在");
        }

        // 检查任务是否已经启用
        if (taskIdMap.containsKey(id)) {
            log.warn("定时任务已经启用: {}", id);
            return;
        }

        try {
            // 注册定时任务
            String wheelTaskId = addSchedulerTask(schedulerTask);
            if (wheelTaskId != null) {
                taskIdMap.put(id, wheelTaskId);

                // 修改数据库状态
                repository.update()
                        .set(SysSchedulerTask::getStatus, 1)
                        .where(w -> w.eq(SysSchedulerTask::getId, id))
                        .submit();

                log.info("定时任务启用成功: {}", id);
            }
        } catch (Exception e) {
            log.error("启用定时任务失败: {}", id, e);
            throw new RuntimeException("启用定时任务失败", e);
        }
    }

    public void disable(String id) {
        String wheelTaskId = taskIdMap.remove(id);
        if (wheelTaskId == null) {
            log.warn("定时任务未启用或不存在: {}", id);
            return;
        }

        SysSchedulerTask schedulerTask = repository.queryById(id);
        if (schedulerTask == null) {
            throw new BaseException("定时任务不存在");
        }

        try {
            // 取消时间轮任务
            if (!scheduler.cancelTask(wheelTaskId)) {
                log.warn("时间轮任务取消失败: {}", wheelTaskId);
            }

            // 修改数据库状态
            repository.update()
                    .set(SysSchedulerTask::getStatus, 0)
                    .where(w -> w.eq(SysSchedulerTask::getId, id))
                    .submit();

            log.info("定时任务禁用成功: {}", id);
        } catch (Exception e) {
            log.error("禁用定时任务失败: {}", id, e);
            throw new BaseException("禁用定时任务失败: " + e.getMessage());
        }
    }

    /**
     * 添加定时任务
     * @return 定时任务在时间轮中的id
     */
    private String addSchedulerTask(SysSchedulerTask schedulerTask) {
        if (Strs.isEmpty(schedulerTask.getBeanName())) {
            log.warn("定时任务类名为空: {}", schedulerTask.getId());
            return null;
        }

        try {
            Task task = taskMap.get(schedulerTask.getBeanName());

            if (task instanceof ParameterTask parameterTaskBean) {
                parameterTaskBean.setDbTaskId(schedulerTask.getId());
            }

            // 添加到时间轮
            String wheelTaskId = scheduler.addTask(new TimeWheelTask(schedulerTask.getCron(), task));
            log.info("定时任务创建成功: {} -> {}", schedulerTask.getId(), wheelTaskId);
            return wheelTaskId;

        } catch (Exception e) {
            log.error("创建定时任务失败: {}", schedulerTask.getId(), e);
            return null;
        }
    }
}